ASM 汇编语言 14

  • Created on 2014-11

教材:《汇编语言》(第二版)王爽 著 清华大学出版社

章十七、使用BIOS进行键盘输入和磁盘读写

键盘输入:最基本的输入
磁盘:最常用的储存设备
BIOS:为以上两种外设提供了最基本的中断例程


17.1 int 9 中断例程对键盘输入的处理

一般键盘输入,在CPU执行完int 9中断例程后,都放到键盘缓冲区中。
键盘缓冲区16个字单元,可以存储15个按键的扫描码和对应ASCII码
键盘缓冲区使用环形队列结构管理的内存区。

int 9 中断例程对键盘输入的处理方法:


17.2 使用 int 16h 中断例程读取键盘缓冲区

BIOS 提供了 int 16h 中断例程,它包含功能
从键盘缓冲区中读取一个键盘输入,功能编号为0

(例)
mov ah, 0
int 16h
结果:(ah)=扫描码,(al)=ASCII码。
功能:
(1)检测键盘缓冲区是否有数据;
(2)没有则重复第一步
(3)读取缓冲区第一个字单元的键盘输入;
(4)将读取的扫描码送入ah,ASCII码送入al;
(5)将已读取的键盘输入从缓冲区中删除。
*. 具体例子,请看原书P303

可见,BIOS的int 9int 16h中断例程是一对相互配合的程序。
int 9 向缓冲区写,int 16h 从缓冲区读,调用时机不同
int 9 在键按下时,它就写入;int 16h 则是被应用程序调用时,它才去读。


编程:接收用户的键盘输入,输入r,将屏幕字符设置为红色;
          g则设为绿色; b则设为蓝色。
源码:
assume cs:code
code segment
start:
     mov ah, 0
     int 16h
    
     mov ah, 1
     cmp al, 'r'
     je red
     cmp al, 'g'
     je green
     cmp al, 'b'
     je blue

     jmp short sret

red:
     shl ah, 1
green:
     shl ah, 1

blue:
     mov bx, 0b800h
     mov es, bx
     mov bx, 1
    
     mov cx, 2000
c0:
     and byte ptr es:[bx], 11111000b
     or es:[bx], ah

     inc bx
     inc bx
     loop c0
    
sret:
     mov ax, 4c00h
     int 21h
code ends
end start


17.3 字符串的输入
最基本的字符串输入程序,需具备以下功能:
(1)在输入的同时需要显示这个字符串;
(2)一般在输入回车符后,字符串输入结束;
(3)能够删除已经输入的字符。

编程:实现以上3个基本功能,参数如下——
          (dh)、(dl)=字符串在屏幕上显示的行、列位置;
          ds:si指向字符串的储存空间,字符串以0为结束符。
实现思路:详看原书P304~305

处理过程
(1)调用int 16h 读取键盘输入
(2)若是字符,入栈,显示栈中所有字符;继续执行(1);
(3)若是退格键,一个字符出栈,显示栈中所有字符;继续执行(2);
(4)若是Enter键,向栈压入0,返回。

源码:
     其中子程序charstack的子程序的参数说明:
     (ah)=功能号,0表示入栈,1表示出栈,2表示显示;
     ds:si指向字符栈空间
     入栈:(al)=入栈字符;
     出站:(al)=出栈返回的字符;
     显示:(dh)、(dl)=字符串在屏幕上显示的行、列位置。

assume cs:code
stack segment
     db 64 dup (0)
stack ends
code segment
start:
     mov ax, stack
     mov ds, ax
     mov si, 0     ;ds:si指向charstack的字符栈空间

     mov dh, 0     ;显示在第0行
     mov dl, 0     ;显示在第0列
     call getstr
    
     mov ax, 4c00h
     int 21h
    
getstr:
     push ax
getstrs:
     ;获取键盘输入
     mov ah, 0
     int 16h

    
     cmp al, 20h
     jb not_char     ;ASCII码小于20h,说明不是字符
    
     mov ah, 0     ;调用charstack的0号子程序
     call charstack     ;字符入栈
     mov ah, 2     ;调用charstack的2号子程序
     call charstack     ;显示栈中的字符

    
     jmp getstrs

not_char:
     cmp ah, 0eh     ;退格键的扫描码
     je backspace
     cmp ah, 1ch     ;回车键的扫描码
     je enter_btn

    
     jmp getstrs

backspace:
     mov ah, 1     ;调用charstack的1号子程序
     call charstack     ;字符出栈
     mov ah, 2     ;类同上
     call charstack     ;显示栈中的字符
    
     jmp getstrs
    
enter_btn:
     mov al, 0
     mov ah, 0
     call charstack     ;0入栈
     mov ah, 2
     call charstack     ;显示栈中字符
    
     pop ax
     ret
    

charstack:
     jmp short  charstart
table     dw charpush, charpop, charshow
top          dw 0     ;栈顶

    
charstart:
     push bx
     push dx
     push di
     push es
    
     cmp ah, 2
     ja sret
    
     mov bh, 0
     mov bl, ah
     add bx, bx
     jmp word ptr table[bx]
    
charpush:
     mov bx, top
     mov ds:[si][bx], al

     inc top
     jmp sret

charpop:
     cmp top, 0
     je sret
    
     dec top
     mov bx, top
     mov al, ds:[si][bx]

     jmp sret
    
charshow:
     mov bx, 0b800h
     mov es, bx
    
     mov ah, 0
     mov al, 160
     mul dh     ;dh:显示在第几行
     mov di, ax
    
     add dl, dl     ;dl:显示在第几列
     mov dh, 0
     add di, dx     ;di:对应的显示缓冲区的偏移量

    
     mov bx, 0
    
charshows:
     cmp bx, top
     jne not_empty
     mov byte ptr es:[di], ' '
     jmp sret
not_empty:
     mov al, ds:[si][bx]
     mov es:[di], al
     mov byte ptr es:[di + 2], ' '     ;设置下一个显示位为空

     inc bx
     inc di
     inc di
     jmp charshows

sret:
     pop es
     pop di
     pop dx
     pop bx
     ret
    
code ends
end start



17.4 应用 int 13h 中断例程对磁盘进行读写
以3.5英寸软盘为例讲解(无法测试,只能做简单的笔记)。
3.5英寸软盘:2面 * 80磁道 * 18扇区 * 512字节 = 1440KB ≈ 1.44MB

int 13h 入口参数:
(ah)=int 13h的功能号
          2:读扇区;3:写扇区
(al)=读/写的扇区数
(ch)=磁道号
(cl)=扇区号
(dh)=磁头号(对于软盘即面号,因为一个面用一个磁头来读写)
(dl)=驱动器号     软驱从0开始,0:软驱A,1:软驱B;
                         硬盘从80h开始,80h:硬盘C,81h:硬盘D
es:bx 指向接受从扇区读入数据的内存区。

返回参数:
操作成功:(ah)=0,(al)=读/写的扇区数
操作失败:(ah)=出错代码


实验17 编写包含多个功能子程序的中断例程
以3.5英寸软盘为对象编写(无法测试,只能简单描述题目)。



课程设计2
(完成并不现实:因为当前使用电脑CPU为64位,
     而非16位的8086CPU,即使编写的汇编程序也无法测试)


0%